/**
 *	Yggdrasil World Framework Toolkit
 *	(A component of the NeuroCoSA toolkit)
 *	Copyright (C) 2001-5 Stuart Meikle.
 *
 *	This is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU Lesser General Public
 *	License as published by the Free Software Foundation; either
 *	version 2.1 of the License, or (at your option) any later version.
 *
 *	This library is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *	Lesser General Public License for more details.
 *
 * @author	Stuart Meikle
 * @version	2006-halloween
 * @license	LGPL
 */

package org.stumeikle.Yggdrasil;

import java.net.*;
import java.io.*;
import java.util.*;
import org.stumeikle.NeuroCoSA.DataBlock;

// 20031106 stumeikle 	initial version
//

/** Body class. 
 *  What Neurocosa systems live in. In some regards an interface between the world and the 
 *  Neurocosa brains. Works FOR THE WORLD, has access to the world structures/maps and limits and
 *  changes the actions provided by the brain. provides feedback. Body needs to be serializable
 *  so that bodies can be written to file. This is generally only needed for the components of
 *  the world which are non-neurocosa system. (Eg critters and the like)
 *
 *  The Body class needs to be overloaded by the user. 
 */
public class	Body implements Serializable  //needs to be serializable for the pingus etc
{
    static final long    serialVersionUID = BodySerialID.Body;
    
    DataBlock		iSenses;		/** For passing senses to the body */
    DataBlock		iActions;	/** for retrieving actions from the body */
    Life		iLife;		/** Non null if there is a tcp/ip connection to a brain */
    boolean		iSendSenses;	
    long		iLastActionV;
    long		iLastSenseV;
	
    //BodyDescription	description;	/** The description of the body in the world */

    /** Constructor.
     * 
     */
    public Body()
    {
        iLife = null;
	iSenses = null;
	iActions = null;
	iSendSenses = true;
	iLastActionV = -1;
	iLastSenseV = -1;
    }

    /** called by the world during instanciation
     */
    public void	setLife( Life l )
    { iLife = l; }	
    

    /** cross thread things. want to be synchronised ? probably FIX
     */
    public void	exportSenses()
    {
	//we can export senses at any rate, certainly faster than
	//what the client can receive.
	//so. update the local senses variable here but only send the
	//senses out to the client when we have received an action
	//block back
        if (iLife!=null && iLife.isReady() && iSenses!=null && iSenses.getVersion() > iLastSenseV)
	{
	    if  (iSendSenses == true)
	    {
//System.out.println("Body, sending senses, v=" + iSenses.getVersion());
		//store the senses ptr in the life structure
		iLife.setSenses(iSenses);
		iLastSenseV = iSenses.getVersion();

		//unblock the life thread so that it can process and send out
		iLife.interrupt();
		Thread.yield();

		iSendSenses = false;
	    }
	}
    }

    /** cross thread things. want to be synchronised ? probably FIX
     */
    public void	importActions()
    {
        if (iLife!=null)
	{
	    iActions = iLife.getActions();
//	    System.out.println("DEBUG: body, importing actions, type=" +
//	    			iActions.getClass().getName() + " version= " +iActions.getVersion());
	    if (iActions.getVersion() > iLastActionV)
	    {
		iLastActionV= iActions.getVersion();
		iSendSenses = true;
  	    }
	}
	else
	    iActions = null;
    }

    /** can be overloaded, eg by critters
     */
    public DataBlock	getActions()
    {
        return iActions;
    }
    
    /** can be overloaded, eg by critters
     */
    public void	setSenses( DataBlock s )
    {
        iSenses = s;
    }

//    public BodyDescription	getBodyDescription()
//    { return description; }

    //======================================== overload these ====================================
    public long	getUpdateTime()
    { return 0; } //run for ever

    public void	setNextUpdateTime(long t)
    {}

    public void	generateSenses()
    {
        System.out.println("Body: this base fucntion should never be called!");
    }

    public void	updateBodyPhysics()
    {
    	System.out.println("Body: please overload update body physics!");
    }

    /** should return true if the creature is dead and needs to be removed. 
     */
    public boolean	deadAndBuried()
    { return false; }
}

